﻿using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Xml;
using UnityView.Xml;
using UnityEngine;
using UnityEngine.UI;
using Object = UnityEngine.Object;

namespace UnityView
{
    public enum Orientation
    {
        Vertical,
        Horizontal
    }

    public enum AnchorAlignment
    {
        Center,
        TopLeft,
        TopRight,
        BottomLeft,
        BottomRight,
        CentralTop,
        CentralBottom,
        CentralLeft,
        CentralRight,
        MidLeft_Up,
        MidLeft_Down,
        MidRight_Up,
        MidRight_Down,
        MidTop_Left,
        MidTop_Right,
        MidBottom_Left,
        MidBottom_Right,
    }

    public interface IViewLayout
    {
        float Width { get; }
        float Height { get; }
        RectTransform RectTransform { get; }
        IViewLayout ParentView { set; get; }
        void AddSubview(IViewLayout view);
        void RemoveSubview(IViewLayout view);
        void Destroy();
    }

    public class UILayout : IViewLayout
    {
        public static string GetMemory(object o) // 获取引用类型的内存地址方法  
        {
            GCHandle h = GCHandle.Alloc(o, GCHandleType.WeakTrackResurrection);

            IntPtr addr = GCHandle.ToIntPtr(h);

            return "0x" + addr.ToString("X");
        }

        public GameObject UIObject { get; protected set; }

        private string _name;

        public string Name
        {
            set
            {
                _name = value;
                UIObject.name = value;
            }
            get { return UIObject.name; }
        }

        // static int count = 0;
        // ~UILayout()
        // {
        //     Debug.Log($"{GetMemory(this)}析构{count++}:   {_name}");
        // }

        public int Layer
        {
            get { return UIObject.layer; }
            set { UIObject.layer = value; }
        }

        public readonly List<IViewLayout> Subviews = new List<IViewLayout>();

        public RectTransform RectTransform { get; protected set; }

        public virtual float Width { get; protected set; }
        public virtual float Height { get; protected set; }

        private AnchorAlignment _anchorAlignment = AnchorAlignment.TopLeft;
        private float _sdx = 1f;
        private float _sdy = -1f;

        public AnchorAlignment AnchorAlignment
        {
            set
            {
                _anchorAlignment = value;
                Vector2[] vectors;
                switch (_anchorAlignment)
                {
                    case AnchorAlignment.TopLeft:
                        vectors = UIConstant.AnchorAlignmentVectors_TopLeft;
                        break;
                    case AnchorAlignment.TopRight:
                        vectors = UIConstant.AnchorAlignmentVectors_TopRight;
                        break;
                    case AnchorAlignment.BottomLeft:
                        vectors = UIConstant.AnchorAlignmentVectors_BottomLeft;
                        break;
                    case AnchorAlignment.BottomRight:
                        vectors = UIConstant.AnchorAlignmentVectors_BottomRight;
                        break;
                    case AnchorAlignment.CentralTop:
                        vectors = UIConstant.AnchorAlignmentVectors_CentralTop;
                        break;
                    case AnchorAlignment.CentralBottom:
                        vectors = UIConstant.AnchorAlignmentVectors_CentralBottom;
                        break;
                    case AnchorAlignment.MidLeft_Up:
                        vectors = UIConstant.AnchorAlignmentVectors_MidLeft_Up;
                        break;
                    case AnchorAlignment.MidLeft_Down:
                        vectors = UIConstant.AnchorAlignmentVectors_MidLeft_Down;
                        break;
                    case AnchorAlignment.MidRight_Up:
                        vectors = UIConstant.AnchorAlignmentVectors_MidRight_Up;
                        break;
                    case AnchorAlignment.MidRight_Down:
                        vectors = UIConstant.AnchorAlignmentVectors_MidRight_Down;
                        break;
                    case AnchorAlignment.MidTop_Left:
                        vectors = UIConstant.AnchorAlignmentVectors_MidTop_Left;
                        break;
                    case AnchorAlignment.MidTop_Right:
                        vectors = UIConstant.AnchorAlignmentVectors_MidTop_Right;
                        break;
                    case AnchorAlignment.MidBottom_Left:
                        vectors = UIConstant.AnchorAlignmentVectors_MidBottom_Left;
                        break;
                    case AnchorAlignment.MidBottom_Right:
                        vectors = UIConstant.AnchorAlignmentVectors_MidBottom_Right;
                        break;
                    default:
                        vectors = UIConstant.AnchorAlignmentVectors_Center;
                        break;
                }

                _sdx = vectors[0].x;
                _sdy = vectors[0].y;
                RectTransform.pivot = vectors[1];
                RectTransform.anchorMin = vectors[2];
                RectTransform.anchorMax = vectors[3];
            }
            get { return _anchorAlignment; }
        }

        public Vector2 Size
        {
            get { return new Vector2(Width, Height); }
        }

        [Animatable]
        public Vector3 Scale
        {
            set
            {
                if (UIAnimation.OnAnimate())
                {
                    UIAnimation.Append(new ScaleAction(RectTransform, RectTransform.localScale, value));
                }
                else
                {
                    RectTransform.localScale = value;
                }
            }
            get { return RectTransform.localScale; }
        }

        // 矩形布局
        public Rect Rect
        {
            set
            {
                RectTransform.anchorMin = value.min;
                RectTransform.anchorMax = value.max;
                RectTransform.offsetMin = Vector2.zero;
                RectTransform.offsetMax = Vector2.zero;
                RectTransform.localScale = Vector3.one;
                Vector3[] vectors = new Vector3[4];
                RectTransform.GetWorldCorners(vectors);
                Width = vectors[2].x - vectors[1].x;
                Height = vectors[1].y - vectors[0].y;
            }
            get { return GetRect(RectTransform); }
        }

        protected Frame frame;

        public Frame Frame
        {
            set
            {
                frame = value;
                Width = value.Size.x;
                Height = value.Size.y;
                RectTransform.anchoredPosition = new Vector3(value.Origin.x * _sdx, value.Origin.y * _sdy, 0);
                RectTransform.sizeDelta = value.Size;
                RectTransform.localScale = Vector3.one;
            }
            get { return frame; }
        }

        public Frame3D Frame3D
        {
            set
            {
                Width = value.Size.x;
                Height = value.Size.y;
                RectTransform.anchoredPosition3D = value.Position;
                RectTransform.sizeDelta = value.Size;
                RectTransform.localScale = Vector3.one;
            }
        }

        public float Depth
        {
            set
            {
                var v = RectTransform.anchoredPosition;
                RectTransform.anchoredPosition3D = new Vector3(v.x, v.y, value);
            }
            get { return RectTransform.anchoredPosition3D.z; }
        }

        // 标准化矩形布局
        [Animatable]
        public UIRect UIRect
        {
            set
            {
                Rect rect = GetRect(RectTransform.parent.GetComponent<RectTransform>());
                if (UIAnimation.OnAnimate())
                {
                    // UIAnimation.Append(new RectAction(this, value, RectTransform.anchorMin, RectTransform.anchorMax,
                    //     new Vector2(value.Left / rect.width, (rect.height - value.Bottom) / rect.height),
                    //     new Vector2(value.Right / rect.width, (rect.height - value.Top) / rect.height)));
                }
                else
                {
                    RectTransform.anchorMin = new Vector2(value.Min.x, 1 - value.Max.y);
                    RectTransform.anchorMax = new Vector2(value.Max.x, 1 - value.Min.y);
                    RectTransform.offsetMin = RectTransform.offsetMax = Vector2.zero;
                    // Width = value.Width;
                    // Height = value.Height;
                }
            }
        }

        // 标准化边框布局
        [Animatable]
        public Frame UIFrame
        {
            set
            {
                Rect rect = GetRect(RectTransform.parent.GetComponent<RectTransform>());
                // RectTransform.pivot = new Vector2(0, 1);
                if (UIAnimation.OnAnimate())
                {
                    UIAnimation.Append(new FrameAction(this, RectTransform.anchorMin, RectTransform.sizeDelta,
                        new Vector2(value.Origin.x / rect.width, (rect.height - value.Origin.y) / rect.height),
                        value.Size));
                }
                else
                {
                    frame = value;
                    Width = value.Size.x;
                    Height = value.Size.y;
                    RectTransform.anchoredPosition = new Vector3(value.Origin.x * _sdx, value.Origin.y * _sdy, 0);
                    RectTransform.sizeDelta = value.Size;
                    RectTransform.localScale = Vector3.one;
                }
            }
        }

        #region Anchor

        public float Anchor_Top => RectTransform.anchoredPosition.y;

        public Vector2 Anchor_TopLeft =>
            new Vector2(-RectTransform.anchoredPosition.x, RectTransform.anchoredPosition.y);

        #endregion

        public void FillParent()
        {
            RectTransform.anchorMin = Vector2.zero;
            RectTransform.anchorMax = Vector2.one;
            RectTransform.offsetMin = RectTransform.offsetMax = Vector2.zero;
            RectTransform.anchoredPosition3D = Vector3.zero;
        }

        public virtual void OnLayout()
        {
        }

        public Vector2 Origin
        {
            get
            {
                Vector3[] corners = new Vector3[4];
                RectTransform.GetWorldCorners(corners);
                return new Vector2(corners[1].x, Screen.height - corners[1].y);
            }
        }

        [Animatable]
        public Quaternion Rotation
        {
            set
            {
                if (UIAnimation.OnAnimate())
                {
                    UIAnimation.Append(new RotateAction(this, RectTransform.rotation, value));
                }
                else
                {
                    RectTransform.rotation = value;
                }
            }
            get { return RectTransform.rotation; }
        }

        [Animatable]
        public void RotateAngle(float angle)
        {
            if (UIAnimation.OnAnimate())
            {
                UIAnimation.Append(new RotateAngleAction(this, RectTransform.rotation, angle));
            }
            else
            {
                RectTransform.Rotate(Vector3.forward, angle);
            }
        }

        public UILayout(string name = "UILayout") : this(UICanvas.GetInstance(), name)
        {
        }

        public UILayout(RectTransform transform, string name = "UILayout")
        {
            UIObject = name == null ? new GameObject() : new GameObject(name);
            UIObject.layer = UIConstant.LayerUI;
            RectTransform = UIObject.AddComponent<RectTransform>();
            RectTransform.localScale = UICanvas.CanvasScale;
            RectTransform.pivot = RectTransform.anchorMin = RectTransform.anchorMax = new Vector2(0, 1);
            _name = name;
            RectTransform.SetParent(transform);
        }

        public UILayout(IViewLayout parent, string name = "UILayout")
        {
            UIObject = name == null ? new GameObject() : new GameObject(name);
            UIObject.layer = UIConstant.LayerUI;
            RectTransform = UIObject.AddComponent<RectTransform>();
            RectTransform.localScale = UICanvas.CanvasScale;
            RectTransform.pivot = RectTransform.anchorMin = RectTransform.anchorMax = new Vector2(0, 1);
            _name = name;
            parent.AddSubview(this);
        }

        public UILayout(GameObject gameObject)
        {
            UIObject = gameObject;
            _name = gameObject.name;
            UIObject.layer = UIConstant.LayerUI;
            RectTransform = gameObject.GetComponent<RectTransform>() ?? gameObject.AddComponent<RectTransform>();
        }

        // 根据一个xml文件初始化视图
        public UILayout(XmlNode node)
        {
            XmlAttributeCollection attrs = node.Attributes;
            if (attrs == null) return;
            Layout(attrs);
        }

        public static UILayout EmptyLayout(RectTransform parent, string name = "Empty Layout")
        {
            UILayout layout = new UILayout(parent) {Name = name};
            layout.RectTransform.SetParent(parent);
            layout.RectTransform.sizeDelta = Vector2.zero;
            return layout;
        }

        public void Layout(XmlAttributeCollection attrs)
        {
            float width = 0;
            float height = 0;

            if (attrs.HasKey("frame"))
            {

            }
            else if (attrs.HasKey("rect"))
            {
                
            }
            else if (attrs.HasKey("width"))
            {
                string ws = attrs["width"].Value;
                switch (ws)
                {
                    case "fill":
                        if (attrs.HasKey("height"))
                        {

                        }
                        else
                        {
                            width = float.Parse(ws);
                        }
                        break;
                    default:
                        width = float.Parse(ws);
                        break;
                }
                height = attrs.TryGetFloat("height");
            }
            else if (attrs.HasKey("height"))
            {
                string hs = attrs["width"].Value;
                switch (hs)
                {
                    case "fill":
                        if (attrs.HasKey("width"))
                        {

                        }
                        else
                        {
                            height = float.Parse(hs);
                        }
                        break;
                    default:
                        height = float.Parse(hs);
                        break;
                }
                width = attrs.TryGetFloat("width");
            }

            Frame = new Frame(0, 0, width, height);
        }

        // 是否可见
        public bool Visible
        {
            get => UIObject.activeSelf;
            set => UIObject.SetActive(value);
        }

        private IViewLayout _parentView;

        public IViewLayout ParentView
        {
            set
            {
                if (value == null) return;
                _parentView = value;
                RectTransform.SetParent(value.RectTransform);
            }
            get { return _parentView; }
        }

        public virtual void Destroy()
        {
            foreach (var subview in Subviews)
            {
                subview.Destroy();
            }

            Subviews.Clear();
            Object.Destroy(UIObject);
        }

        public virtual void AddSubview(IViewLayout view)
        {
            if (view == null) return;
            view.ParentView = this;
            Subviews.Add(view);
        }

        public virtual void RemoveSubview(IViewLayout view)
        {
            if (view == null) return;
            view.ParentView = null;
            Subviews.Remove(view);
        }

        public virtual void ClearSubviews()
        {
            foreach (IViewLayout subview in Subviews)
            {
                subview.Destroy();
            }

            Subviews.Clear();
        }

        public static Rect GetRect(RectTransform transform)
        {
            Vector3[] corners = new Vector3[4];
            transform.GetWorldCorners(corners);
            return new Rect(corners[0].x, corners[0].y, corners[2].x - corners[0].x, corners[2].y - corners[0].y);
        }

        public static void RectFill(UILayout layout)
        {
            RectFill(layout.RectTransform);
            // RectTransform parent = layout.RectTransform.parent.GetComponent<RectTransform>();
            // RectFill(layout.RectTransform);
            // Rect rect = GetRect(parent);
            // layout.Width = rect.width;
            // layout.Height = rect.height;
        }

        public static void RectFill(RectTransform rectTransform, float depth = 0)
        {
            rectTransform.anchoredPosition3D = new Vector3(0, 0, depth);
            rectTransform.anchorMin = Vector2.zero;
            rectTransform.anchorMax = Vector2.one;
            rectTransform.offsetMin = Vector2.zero;
            rectTransform.offsetMax = Vector2.zero;
        }

        public static void FrameFill(UILayout layout)
        {
            FrameFill(layout.RectTransform);
        }

        public static void FrameFill(RectTransform rectTransform)
        {
            var transform = rectTransform.parent as RectTransform;
            if (transform == null) return;
            Vector3[] vectors = new Vector3[4];
            transform.GetWorldCorners(vectors);
        }

        public static void RectToCenterZoom(RectTransform rectTransform, float zoom)
        {
            var minOffset = (1f - zoom) / 2f;
            var maxOffset = zoom + minOffset;
            rectTransform.anchorMin = new Vector2(minOffset, minOffset);
            rectTransform.anchorMax = new Vector2(maxOffset, maxOffset);
            rectTransform.offsetMin = Vector2.zero;
            rectTransform.offsetMax = Vector2.zero;
        }

        // 给Layout添加一个下划线
        public static void AddUnderLine(RectTransform parent, float height, Color color)
        {
            GameObject underLine = new GameObject("Under Line");
            underLine.AddComponent<CanvasRenderer>();
            RectTransform rectTransform = underLine.AddComponent<RectTransform>();
            Image image = underLine.AddComponent<Image>();
            image.color = color;
            rectTransform.SetParent(parent);
            rectTransform.anchorMax = new Vector2(1f, height / parent.rect.height);
            rectTransform.anchorMin = rectTransform.offsetMin = rectTransform.offsetMax = Vector2.zero;
        }
    }
}